home *** CD-ROM | disk | FTP | other *** search
/ QuickTime 1.0 for Developers / QuickTime 1.0 for Developers.iso / Programming Stuff / Sample Code / MovieConstruction / Movie Construction FD.c < prev    next >
C/C++ Source or Header  |  1991-09-05  |  12KB  |  437 lines

  1. /************************************
  2. *
  3. * file: Movie Construction FD.c
  4. *
  5. * This program creates a movie by drawing
  6. * frames and adding adding them one at a
  7. * time to the movie.
  8. *
  9. * This program uses the sequence compression commands
  10. * which make smaller movie files by only saving
  11. * the changes between frames
  12. *
  13. *
  14. * by Rich Williams
  15. * January, 1991
  16. *    updated to 4.04 interfaces
  17. *
  18. *    8/91 added making component call to make a preview
  19. *    Updated to MPW/Think 5.0/DSG interfaces 9/91 Chris Thorman
  20. *        
  21. ***************************************************/
  22.  
  23. #include "Movies.h"
  24. #include "QuickTimeComponents.h"
  25.  
  26. #include <Memory.h>
  27. #include <Fonts.h>
  28. #include <Palettes.h>
  29. #include <OSEvents.h>
  30. #include <Menus.h>
  31. #include <Sound.h>
  32. #include <ToolUtils.h>
  33. #include <Desk.h>
  34. #include <Resources.h>
  35. #include <Errors.h>
  36. #include <Packages.h>
  37.  
  38. /************************************
  39. * Limits and Konstants
  40. ************************************/
  41.  
  42. #define kFrameX 120                /* Width & Height */
  43. #define kFrameY 100
  44. #define kPixelSize 32 
  45. #define kFrameCnt 25            /* Number of frames to do */
  46. #define kTimeScale 10            /* frames per second */
  47.  
  48. /* The fixed point number for 1.00 */
  49. #define x1Rate (Fixed) 1<<16
  50.  
  51. /************************************
  52. * Types and globals
  53. ************************************/
  54.  
  55. /* Drawer receives these fields */
  56. typedef struct
  57.     {
  58.     long frameX,frameY;
  59.     long frameCnt;
  60.     long pixelSize;
  61.     } animationLimits;
  62.  
  63. /************************************
  64. * Prototypes
  65. ************************************/
  66. static void InitToolbox(void);
  67. static void MakeFrames(animationLimits *);
  68. static void ConstructMovie(void);
  69. void MakePreview(FSSpecPtr theFile, short resRefNum);
  70.  
  71. void main(void);
  72.  
  73. /************************************
  74. *
  75. * InitToolbox()
  76. *  Start up the tool (and the movie tools!)
  77. *
  78. ************************************/
  79. void InitToolbox()
  80. {
  81.     OSErr    theErr;
  82.  
  83.     MaxApplZone();
  84.     InitGraf(&qd.thePort);
  85.     InitFonts();
  86.     FlushEvents(0xffff,0);
  87.     InitWindows();
  88.     InitMenus();
  89.     InitDialogs(0);
  90.     TEInit();
  91.     InitCursor();
  92.     
  93.     theErr = EnterMovies();    /* Don't forget this.  Real men use Alert Dialogs */
  94.     if (theErr) DebugStr((StringPtr) "\pEnterMovies Failed");
  95. }
  96.  
  97.  
  98. /************************************
  99. *
  100. * Construct Movie()
  101. *  Make a window and call MakeFrames
  102. *
  103. ************************************/
  104. void ConstructMovie()
  105. {
  106.     WindowPtr w;
  107.     Rect r;
  108.     animationLimits al;
  109.  
  110.     r.left = r.top = 0;
  111.     r.right = kFrameX;
  112.     r.bottom = kFrameY;
  113.  
  114.     OffsetRect(&r,100,100);
  115.     w = NewCWindow(0,&r,(StringPtr)"\pFrames",true,0,(WindowPtr)-1,true,0);
  116.     SetPort(w);
  117.  
  118.     al.frameX = kFrameX;
  119.     al.frameY = kFrameY;
  120.     al.frameCnt = kFrameCnt;
  121.     al.pixelSize = kPixelSize;
  122.  
  123.     MakeFrames(&al);        /* write out lots of frames */
  124.  
  125.     CloseWindow(w);
  126. }
  127.  
  128.  
  129. /************************************
  130. *
  131. * MakeFrames(al)
  132. *  Here is where all the work happens
  133. *
  134. ************************************/
  135. void MakeFrames(al)
  136.  
  137. animationLimits *al;
  138.  
  139. {
  140.     short         theErr;                            /* latest error return */
  141.     short         resRefNum;
  142.     long         i;                                /* the usual miscellaneous integer */
  143.     
  144.     /* Stuff for creating the file */
  145.     Point        dlgPos = {100,100};                /* Position the dialog box */
  146.     SFReply        sfr;                            /* StdFile reply */
  147.     FSSpec        mySpec;                            /* Data structure with filename, etc. */
  148.     short         resId;
  149.                 
  150.     Movie        gMovie;                            /* Our movie, track and media */
  151.     Track        gTrack;
  152.     Media        gMedia;
  153.  
  154.     /* Stuff for drawing our frames */
  155.     GWorldPtr     myGWorld,oldGWorld;
  156.     GDHandle     oldGDevice;
  157.     PixMap         *pm,**pmH;                        /* our offscreen pixmap                */
  158.     char         c[30];                            /* a string, for NumToString        */
  159.     Rect         r,r2;
  160.     
  161.     /* Stuff for the compressor */
  162.     char         **compressedFrameBitsH;            /* Buffer for the compressed data    */
  163.     long         maxCompressedFrameSize;            /* Max size of compressed frame        */
  164.     long        compressedFrameSize;            /* Size of current compressed frame */
  165.     CodecType    codecType;                        /* Type of codec to use JPEG etc    */
  166.     CompressorComponent codecID;                /* Which variation of codecType to use */
  167.     short        theDepth;                        /* Color depth to compress to        */
  168.     CodecQ         theQuality;                        /* Quality to compress to            */
  169.     ImageDescription    **imageDescriptionH;    /* Contains info about the sample    */
  170.     
  171.     /* For frame differencing, we also have these */
  172.     ImageSequence    seqID;                        /* Which sequence is being compressed */
  173.     unsigned char    similarity;                    /* Measure of how similar the frame is to the previous one */
  174.     long    keyFrameRate;                        /* # samples per key frame */    
  175.     CodecQ mQuality;                            /* Motion quality */
  176.  
  177.     /* Stuff for adding the sample */
  178.     TimeValue     sampTime;                        /* Time sample is added to media */
  179.     
  180.     /******************************
  181.     *
  182.     * Set values for Road Pizza compression
  183.     * You would let the user pick it with a dialog
  184.     *
  185.     *******************************/
  186.     codecID = anyCodec;
  187.     codecType = (CodecType) 'rpza';
  188.     theDepth = 16;
  189.     theQuality = 0x200;                            /* Quality is 0x100 to 0x300 */
  190.  
  191.     mQuality = 0x200;
  192.     keyFrameRate = 10;                            /* 1 keyframe every 10 frames */
  193.  
  194.     /******************************
  195.     *
  196.     * First we make an empty movie
  197.     *
  198.     *******************************/
  199.     /* Prompt the user for a file name and create it */
  200.     SFPutFile(dlgPos, (StringPtr) "\pMovie file to create:",(StringPtr)"\pTempMovie",nil,&sfr);
  201.     if (!sfr.good)
  202.         return;                                    /* Return if cancel pressed */
  203.  
  204.     ClearMoviesStickyError();                    /* Clear any old errors */
  205.  
  206.     theErr = FSMakeFSSpec(sfr.vRefNum, 0, (unsigned char *) sfr.fName, &mySpec);
  207.     if (theErr == fnfErr) theErr = 0;
  208.     if (theErr) DebugStr((StringPtr) "\pFSMakeFSSpec Failed");
  209.  
  210.     theErr = CreateMovieFile(  &mySpec, 'TVOD',0,createMovieFileDeleteCurFile,&resRefNum,&gMovie);
  211.     if (theErr) DebugStr((StringPtr) "\pCreateMovieFile Failed");
  212.  
  213.     /* Create the track and media */
  214.     gTrack = NewMovieTrack(gMovie,(long)kFrameX<<16,(long)kFrameY<<16,0);
  215.     if (theErr = GetMoviesError()) DebugStr((StringPtr) "\pNewMovieTrack Failed");
  216.  
  217.     gMedia = NewTrackMedia(gTrack, VideoMediaType, kTimeScale, nil,(OSType) nil);
  218.     if (theErr = GetMoviesError()) DebugStr((StringPtr) "\pNewTrackMedia Failed");
  219.  
  220.     theErr = BeginMediaEdits( gMedia );        /* We do this since we are adding samples to the media */
  221.     if (theErr) DebugStr((StringPtr) "\pBeginMediaEdits Failed");
  222.  
  223.     /******************************
  224.     *
  225.     * Now make a new GWorld to draw the frames to be compressed
  226.     *
  227.     *******************************/
  228.     GetGWorld(&oldGWorld,&oldGDevice);                    /* save the old port */
  229.  
  230.     r.left = r.top = 0;
  231.     r.right = al->frameX;
  232.     r.bottom = al->frameY;
  233.  
  234.     if (theErr = NewGWorld(&myGWorld,al->pixelSize,&r,nil,nil,0))
  235.         DebugStr((StringPtr) "\pNewGWorld Failed");
  236.     pmH = myGWorld->portPixMap;                            /* GetGWorldPixMap doesn't always work */
  237.     LockPixels(pmH);
  238.     HLock((Handle)pmH);
  239.     pm = *pmH;                                            /* pm is pointer to pixel-map */
  240.  
  241.     /******************************
  242.     *
  243.     * Now make the buffers and stuff for the compressor
  244.     *
  245.     *******************************/
  246.     imageDescriptionH = (ImageDescription **)NewHandle( 4 );    /* handle for image descriptor */
  247.  
  248.     theErr = GetMaxCompressionSize(&pm,&r,theDepth,theQuality,
  249.                         codecType,codecID,&maxCompressedFrameSize);    /* How big a buffer do we need? */
  250.  
  251.     if (theErr) DebugStr((StringPtr) "\pGetMaxCompressionSize Failed");
  252.  
  253.     compressedFrameBitsH = NewHandle(maxCompressedFrameSize);    /* Make the buffer */
  254.     if (!compressedFrameBitsH) DebugStr((StringPtr) "\pUnable to allocate compression buffer");
  255.  
  256.     HLock(compressedFrameBitsH);
  257.  
  258.     /******************************
  259.     *
  260.     * Tell the codec manager we are about to start a sequence 
  261.     *
  262.     *******************************/
  263.  
  264.     theErr = CompressSequenceBegin( &seqID,
  265.                     &pm, nil,
  266.                     &r, nil,
  267.                     theDepth, codecType, codecID,
  268.                     theQuality, 
  269.                     mQuality, keyFrameRate,
  270.                     nil /* no clut */, 
  271.                     codecFlagUpdatePrevious, 
  272.                     imageDescriptionH);
  273.  
  274.     if (theErr) DebugStr((StringPtr) "\pCompressSequenceBegin Failed");
  275.  
  276.     /******************************
  277.     *
  278.     * Now put the movie together one frame at a time
  279.     *
  280.     *******************************/
  281.     for(i = 0; i<al->frameCnt; i++)
  282.     {
  283.         if(Button())                        /* A terrific user interface */
  284.         {
  285.             FlushEvents(0xffff,0);
  286.             ExitToShell();
  287.         }
  288.  
  289.         /******************************
  290.         *
  291.         * This is where we draw a single frame of the movie.
  292.         * We're only drawing black and white here, into our big
  293.         * 32-bit offscreen GWorld, because RAM is so cheap.
  294.         *
  295.         *******************************/
  296.  
  297.         SetGWorld(myGWorld,nil);
  298.         EraseRect(&r);                        /* erase the whole area to white */
  299.  
  300.         MoveTo(20,20);
  301.         NumToString(i+1,(StringPtr)&c);
  302.         DrawString((StringPtr)&c);
  303.  
  304.         r2 = r;
  305.         r2.bottom = (long)r2.bottom * i / (al->frameCnt-1);
  306.         InvertRect(&r2);
  307.  
  308.         /******************************
  309.         *
  310.         * Go back to the old GWorld (the Window)
  311.         * and copybit the frame into it for something to watch
  312.         *
  313.         *******************************/
  314.  
  315.         SetGWorld(oldGWorld,oldGDevice);
  316.         CopyBits((BitMap *) pm,(BitMap *) *(PixMapHandle)(qd.thePort->portBits.baseAddr),&r,&r,0,0);
  317.  
  318.         /******************************
  319.         *
  320.         * Compress the Frame
  321.         *
  322.         *******************************/
  323.         
  324.         theErr = CompressSequenceFrame(seqID,
  325.                                         &pm,
  326.                                         &r,
  327.                                         codecFlagUpdatePrevious,
  328.                                         *compressedFrameBitsH,
  329.                                         &compressedFrameSize,
  330.                                         &similarity,
  331.                                         nil);
  332.  
  333.  
  334.  
  335.         if (theErr) DebugStr((StringPtr) "\pCompressSequenceFrame Failed");
  336.  
  337.         /******************************
  338.         *
  339.         * And add it to the media
  340.         *
  341.         *******************************/
  342.         
  343.         theErr = AddMediaSample(gMedia,
  344.                                     compressedFrameBitsH,
  345.                                     0L,
  346.                                     compressedFrameSize,
  347.                                     (TimeValue)1,
  348.                                     (SampleDescriptionHandle) imageDescriptionH,
  349.                                     1L,
  350.                                     similarity?mediaSampleNotSync:0, 
  351.                                     &sampTime);
  352.  
  353.         if (theErr) DebugStr((StringPtr) "\pAddMediaSample Failed");
  354.  
  355.         /* And loop back for the next frame */
  356.     }
  357.  
  358.     /******************************
  359.     *
  360.     * Now close up the movie
  361.     * and throw out our buffers and stuff 
  362.     *
  363.     *******************************/
  364.     theErr = CDSequenceEnd(seqID);                /* Tell the codec we're done with the sequence */
  365.     if (theErr) DebugStr((StringPtr) "\pCDSequenceEnd Failed");
  366.  
  367.     theErr = EndMediaEdits( gMedia );                /* We're done adding samples */
  368.     if (theErr) DebugStr((StringPtr) "\pEndMediaEdits Failed");
  369.  
  370.     theErr = InsertMediaIntoTrack(gTrack,0L,0L,GetMediaDuration(gMedia),x1Rate);
  371.     if (theErr) DebugStr((StringPtr) "\pInsertMediaIntoTrack Failed");
  372.  
  373.     resId = 1;
  374.     theErr = AddMovieResource( gMovie, resRefNum, &resId, (char *)sfr.fName );
  375.     if (theErr) DebugStr((StringPtr) "\pAddMovieResource Failed");
  376.  
  377.     MakePreview(&mySpec,resRefNum);                /* Add a preview to the file */
  378.     
  379.     theErr = CloseMovieFile( resRefNum );
  380.     if (theErr) DebugStr((StringPtr) "\pCloseMovieFile Failed");
  381.  
  382.     DisposeMovie(gMovie);                        /* We don't need the movie anymore */
  383.     DisposHandle(compressedFrameBitsH);
  384.     DisposHandle((Handle)imageDescriptionH);
  385.     DisposeGWorld(myGWorld);
  386.  
  387. }
  388.  
  389. /******************************
  390. *
  391. * MakePreview
  392. *     makes a preview for the movie 
  393. *
  394. *******************************/
  395. void MakePreview(FSSpecPtr theFile, short resRefNum)
  396.  
  397. {
  398.     ComponentInstance        thePreviewMaker;
  399.     Component                thePreviewComponent;
  400.     ComponentDescription    tDesc;
  401.     OSErr    theErr;
  402.     
  403.     /* Find a preview component */
  404.     tDesc.componentType = 'prvt';
  405.     tDesc.componentSubType = 'MooV';
  406.     tDesc.componentManufacturer = 0;
  407.     tDesc.componentFlags = 0;
  408.     tDesc.componentFlagsMask = 0;
  409.     thePreviewComponent = FindNextComponent( (Component) 0,&tDesc);
  410.     
  411.     /* an instance of the component */
  412.     thePreviewMaker = OpenComponent(thePreviewComponent);
  413.  
  414.     if(thePreviewMaker == nil)                /* Did it fail? */
  415.         return;                                
  416.     
  417.     /* Now put the preview into the file  */
  418.     theErr = PreviewerCreatePreviewForResRefNum(thePreviewMaker, resRefNum, theFile, true, nil, nil);
  419.     
  420.     CloseComponent(thePreviewMaker);        /* Throw out the component */
  421.     
  422.     
  423. }
  424.  
  425. /******************************
  426. *
  427. * The main routine
  428. *     It doesn't look like much but I'm proud of it 
  429. *
  430. *******************************/
  431. void main()
  432. {
  433.     InitToolbox();            /* Start up the tools */
  434.     ConstructMovie();        /* Make the movie */
  435. }
  436.  
  437.